﻿using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace XEnamel
{
	public struct MethodDescriptor
	{
		public Type DeclaringType;
		public string MethodName;

		public MethodInfo GetMethodInfo(IEnumerable<Type> types)
		{
			string name = MethodName;
			return DeclaringType.GetMethod(MethodName, types.ToArray())
				?? DeclaringType.GetMethods().Where(x => (x.Name == name) && (x.GetParameters().Count() == types.Count())).First();
		}

		/// <summary>
		/// Convert an array of values to be valid input for this method.
		/// </summary>
		public IEnumerable<Expression> ConvertArguments(IEnumerable<Expression> arguments)
		{
			var parms = GetMethodInfo(arguments.Select(x => x.Type)).GetParameters();
			return Enumerable.Range(0, parms.Count()).Select(index => arguments.ElementAt(index).ChangeType(parms[index].ParameterType).Convert(parms[index].ParameterType));
		}

		/// <summary>
		/// Convert an array of values to be valid input for this method.
		/// </summary>
		public IEnumerable<object> ConvertArguments(IEnumerable<object> arguments)
		{
			var parms = GetMethodInfo(arguments.Select(x => x.GetType())).GetParameters();
			return Enumerable.Range(0, parms.Count()).Select(index => Convert.ChangeType(arguments.ElementAt(index), parms[index].ParameterType));
		}
	}
}